"""
oyObjectPicker by E. Ozgur Yilmaz (c) 2009

v10.6.15

Description :
-------------
a tool for easy animating of picking and releasing of objects

Version History :
-----------------

v10.5.17
- modifications for Maya 2011 and Pymel 1.0.2

v10.5.12
- added support for exploding the whole setup

v9.11.16
- moved to new version numbers system
- reflected the change in axialCorrectionGroup command

v1.2.1
- fixed a little bug in editKeyframesOfObject and addDefaultOptionsToDAGMenu

v1.2.0
- added the ability to use the script from DAGMenu with object specific
  commands
- added setObjectsParent, releaseObjectWithName, fixJumpOnObject,
  editKeyframesOfObject which uses string inputs, to be able to use them in the
  DAGMenu

v1.1.10
- renamed: selectKeyframers is renamed to selectAnimCurves
- improved: setParent now checks for cycle before seting up anything
- improved: releaseObject, editKeyframes, fixJump now checks for empty
  selection list, and the selList is sustained after they finish their job
- improved: setupToBePicked is rewritten
- improved: creating the localParent is improved
- removed: _isOnTop is removed
- removed: _getUsableParents is replaced with _getParents
- removed: _hasEnoughParents is removed

v1.1.9
- fixed: localParent attribute has been left as multi attribute

v1.1.8
- fixed: axialCorrection groups of referenced objects are moving as they are
  setup and the objects transformations become non-zero

v1.1.7
- fixed: the object can now be setup if it is on top of the hierarchy and even
  it is referenced
- fixed: _getUsableParents now returns the correct nodes
- added: now the parent is checked for cycle before setup

v1.1.6
- fixed: _isSetup is causing problems problems to setup the object
- changed: selectKeyframers now selects athe animCurves instead of the
  objects

v1.1.5
- added: setParent, releaseObject, editKeyframes, fixJump functions

v1.1.0
- removed: the concept of remote parents, it doesn't need to be saved in an
  attribute, because it can easly be get from the parentConstraint node
- removed: the setupToBePickedUp from __init__, objects need to be setup
  separatedly from the initilization
- changed: internal private functions are now starting with underscore (_)
  following the Python convention
- changed: all the targets changed to parents
- code cleanup

v1.0.0
- fixed: fixJump now works correctly
- organized the code

v0.9.0RC
- the code is working now, will stay in this version for a while just to
  observe if animators will have any problems

v0.0.2.preAlpha
- changed: rigger uses no remote parents anymore

v0.0.1.preAlpha
- developing version

TODO List :
-----------
- use scriptJobs for auto fixJump functionality
+ check the usage with referenced objects ( allow picking of the object even
  if the object is referenced, if it is in top of the hierarchy )
- option to remove the whole setup and created nodes
- support for scale constraining
- one click multiple object setup
------------------------------------------------------------------------------
"""


__version__ = "9.11.16"



import pymel.core as pm
import oyAuxiliaryFunctions as oyAux


########################################################################
class PickedObject(object):
    """PickedObject class to setup picking and releasing of objects
    """
    
    #----------------------------------------------------------------------
    def __init__( self, _object ):
        # the object
        self._object = oyAux.getValidDagNode( _object )
        assert( isinstance( self._object, pm.nodetypes.Transform ))
        
        # the data
        self._constrainedParent = None
        self._stabilizerParent = None
        self._localParent = None
        self._parentConstraint = None
        
        self._isSetup = False
        # read settings
        self._readSettings()
    
    
    
    #----------------------------------------------------------------------
    def _saveSettings(self):
        """save settings inside objects oyPickerData attribute
        """
        # 
        # data to be save :
        # -----------------
        # 
        # constrainedPrarent node
        # stabilizerParent node
        # parentConstraint node
        # localParent node
        
        # create attributes
        self._createDataAttribute()
        
        # connect constrainedParent node
        pm.connectAttr( self._constrainedParent.name() + ".message", self._object.attr("pickedData.constrainedParent"), f=True )
        
        # connect constrainedParent node
        pm.connectAttr( self._stabilizerParent.name() + ".message", self._object.attr("pickedData.stabilizerParent"), f=True )
        
        # connect parentConstraint node
        pm.connectAttr( self._parentConstraint.name() + ".message", self._object.attr("pickedData.parentConstraint"), f=True )
        
        # connect localParent node
        pm.connectAttr( self._localParent.name() + ".message", self._object.attr("pickedData.localParent"), f=True )
        
        # set stabilizer parent values
        tra = self._stabilizerParent.getAttr('t')
        rot = self._stabilizerParent.getAttr('r')
        sca = self._stabilizerParent.getAttr('s')
        
        self._object.setAttr('pickedData.stabilizerParentInitialData.sPIDposition', tra )
        self._object.setAttr('pickedData.stabilizerParentInitialData.sPIDrotation', rot )
        self._object.setAttr('pickedData.stabilizerParentInitialData.sPIDscale', sca )
    
    
    
    #----------------------------------------------------------------------
    def _readSettings(self):
        """reads settings from objects pickedData attribute\n
        if there is no attribute to read it returns False
        """
        # check if it has pickedData attribute
        if self._object.hasAttr( "pickedData" ):
            
            # get stabilizerParent node
            self._stabilizerParent = oyAux.getValidDagNode( pm.listConnections( self._object.attr("pickedData.stabilizerParent") )[0] )
            
            # get constrainedParent node
            self._constrainedParent = oyAux.getValidDagNode( pm.listConnections( self._object.attr("pickedData.constrainedParent") )[0] )
            
            # get parentConstraint node
            self._parentConstraint = oyAux.getValidDagNode( pm.listConnections( self._object.attr("pickedData.parentConstraint") )[0] )
            
            # get localParent node
            self._localParent = oyAux.getValidDagNode( pm.listConnections( self._object.attr("pickedData.localParent") )[0] )
            
            # set isSetup flag
            self._isSetup = True
            
            return True
        
        return False
    
    
    
    #----------------------------------------------------------------------
    def _createDataAttribute(self):
        """creates attribute in self._object to hold the rawData
        """
        if not self._object.hasAttr( "pickedData" ):
            pm.addAttr( self._object, ln="pickedData", at="compound", nc=6 )
        
        if not self._object.hasAttr( "constrainedParent" ):
            pm.addAttr( self._object, ln="constrainedParent", at="message", p="pickedData" )
        
        if not self._object.hasAttr( "stabilizerParent" ):
            pm.addAttr( self._object, ln="stabilizerParent", at="message", p="pickedData" )
        
        if not self._object.hasAttr( "parentConstraint" ):
            pm.addAttr( self._object, ln="parentConstraint", at="message", p="pickedData" )
        
        if not self._object.hasAttr( "localParent" ):
            pm.addAttr( self._object, ln="localParent", at="message", p="pickedData")
        
        if not self._object.hasAttr("createdNodes"):
            pm.addAttr( self._object, ln="createdNodes", at="message", m=1, p="pickedData")
        
        if not self._object.hasAttr( "stabilizerParentInitialData" ):
            # this attribute should store the default position of the stabilizer parent
            # when the setup is exploded the stabilizer parent should be returned to this local position
            pm.addAttr( self._object, ln="stabilizerParentInitialData", at="compound", nc=3, p="pickedData" )
            
            pm.addAttr( self._object, ln="sPIDposition", at="compound", nc=3, p="stabilizerParentInitialData" )
            pm.addAttr( self._object, ln="sPIDpositionX", at="float", p="sPIDposition" )
            pm.addAttr( self._object, ln="sPIDpositionY", at="float", p="sPIDposition" )
            pm.addAttr( self._object, ln="sPIDpositionZ", at="float", p="sPIDposition" )
            
            pm.addAttr( self._object, ln="sPIDrotation", at="compound", nc=3, p="stabilizerParentInitialData" )
            pm.addAttr( self._object, ln="sPIDrotationX", at="float", p="sPIDrotation" )
            pm.addAttr( self._object, ln="sPIDrotationY", at="float", p="sPIDrotation" )
            pm.addAttr( self._object, ln="sPIDrotationZ", at="float", p="sPIDrotation" )
            
            pm.addAttr( self._object, ln="sPIDscale", at="compound", nc=3, p="stabilizerParentInitialData" )
            pm.addAttr( self._object, ln="sPIDscaleX", at="float", p="sPIDscale" )
            pm.addAttr( self._object, ln="sPIDscaleY", at="float", p="sPIDscale" )
            pm.addAttr( self._object, ln="sPIDscaleZ", at="float", p="sPIDscale" )
    
    
    
    #----------------------------------------------------------------------
    def setupToBePickedUp(self):
        """setups specified object for pick/release sequence
        """
        
        # if it is setup before, don't do anything
        if self._isSetup:
            return
        else:
            self._isSetup = True
        
        # if it is a referenced object and it is not on top of its
        # hierarchy the parents can't be created
        # 
        # so ask the user to use the function
        # in the original scene
        isRef = self._isReferenced( self._object )
        
        parents = self._getParents( self._object )
        parentCnt = len(parents)
        
        # create attributes for data holding
        self._createDataAttribute()
        
        
        if isRef:
            if parentCnt == 0:
                # create parents
                self._createStabilizerParent()
                self._createConstrainedParent()
                
            elif parentCnt == 1:
                # set the available parent as the stabilizer parent
                # and create constrainedParent
                self._stabilizerParent = oyAux.getValidDagNode( parents[0] )
                self._createConstrainedParent()
                
            elif parentCnt >= 2:
                # use directly the parents
                self._stabilizerParent = oyAux.getValidDagNode( parents[0] )
                self._constrainedParent = oyAux.getValidDagNode( parents[1] )
                
        else: # is not referenced
            # create the parents
            self._createStabilizerParent()
            self._createConstrainedParent()
        
        # create localParent
        self._createLocalParent()
        
        # create the parent constraint
        self._createParentConstraint()
        
        # set keyframe colors of the parentConstraint and stabilizerParent
        self._setKeyframeColors()
        
        # save the settings
        self._saveSettings()
        
        # create DAGMenu defualt commands
        self.addDefaultOptionsToDAGMenu()
    
    
    
    #----------------------------------------------------------------------
    def explodeSetup(self):
        """breaks all the setup objects
        """
        if not self._isSetup:
            return
        
        # delete all the constraints
        pm.delete( self._parentConstraint )
        
        # delete stabilizer parent animation curves
        pm.delete( self._stabilizerParent.attr('tx').inputs(),
                   self._stabilizerParent.attr('ty').inputs(),
                   self._stabilizerParent.attr('tz').inputs(),
                   self._stabilizerParent.attr('rx').inputs(),
                   self._stabilizerParent.attr('ry').inputs(),
                   self._stabilizerParent.attr('rz').inputs(),
                   self._stabilizerParent.attr('sx').inputs(),
                   self._stabilizerParent.attr('sy').inputs(),
                   self._stabilizerParent.attr('sz').inputs(),)
        
        # move the stabilizer parent to its default position
        # ( if there is a stabilizerParentInitialData attr )
        if self._object.hasAttr('stabilizerParentInitialData'):
            
            # position
            self._stabilizerParent.setAttr('tx', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDposition.sPIDpositionX'))
            self._stabilizerParent.setAttr('ty', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDposition.sPIDpositionY'))
            self._stabilizerParent.setAttr('tz', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDposition.sPIDpositionZ'))
            
            # rotation
            self._stabilizerParent.setAttr('rx', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDrotation.sPIDrotationX'))
            self._stabilizerParent.setAttr('ry', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDrotation.sPIDrotationY'))
            self._stabilizerParent.setAttr('rz', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDrotation.sPIDrotationZ'))
            
            # scale
            self._stabilizerParent.setAttr('sx', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDscale.sPIDscaleX'))
            self._stabilizerParent.setAttr('sy', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDscale.sPIDscaleY'))
            self._stabilizerParent.setAttr('sz', self._object.getAttr('pickedData.stabilizerParentInitialData.sPIDscale.sPIDscaleZ'))
        
        
        if self._object.hasAttr('pickedData.createdNodes'):
            # delete created nodes
            objectToParent = None
            parentObj = None
            
            nodesToDelete = self._object.attr('pickedData.createdNodes').inputs()
            if self._constrainedParent in nodesToDelete:
                # parent the stabilizer parent to the constrained parents parent
                objectToParent = self._stabilizerParent
                parentObj = self._constrainedParent.getParent()
                if self._stabilizerParent in nodesToDelete:
                    objectToParent = self._object
            
            if objectToParent is not None:
                if parentObj is not None:
                    pm.parent( objectToParent, parentObj )
                else:
                    pm.parent( objectToParent, w=True )
            
            # then delete the nodes
            pm.delete( nodesToDelete )
            
            
        
        # delete picked data attribute on the object
        self._object.attr('pickedData').delete()
        
        # also delete special commands
        self._object.attr('specialCommands').delete()
        self._object.attr('specialCommandLabels').delete()
    
    
    
    #----------------------------------------------------------------------
    def _createLocalParent(self):
        """creates local parent and axial correction group of local parent
        """
        # create the localParent group
        self._localParent = pm.group(em=True, n=self._object.name() + "_localParent" )
        
        # move it to the same place where constrainedParent is
        matrix = pm.xform( self._constrainedParent, q=True, ws=True, m=True )
        pm.xform( self._localParent, ws=True, m=matrix )
        
        # parent it to the constrained parents parent
        parents = pm.listRelatives( self._constrainedParent, p=True)
        
        if len(parents) != 0:
            temp = pm.parent( self._localParent, parents[0], a=True )
            self._localParent = temp[0]
        
        self._localParent = oyAux.getValidDagNode( self._localParent )
        index = self._object.attr('pickedData.createdNodes').numElements()
        self._localParent.attr('message') >> self._object.attr('pickedData.createdNodes['+str(index)+']')
    
    
    
    #----------------------------------------------------------------------
    def _createParentConstraint(self):
        """creates parentConstraint between _localParent and the
        _constrainedParent
        """
        self._parentConstraint = pm.parentConstraint( self._localParent, self._constrainedParent, w=1 )
        
        # set also a keyframe for the localParent to weight 1
        
        # get the weight alias of localParent
        weightAlias = self.getWeightAlias( self._localParent )
        
        frame = 0
        
        weightAlias.setKey( t=frame, ott="step" )
        
        self._setStabilizerKeyframe(frame)
    
    
    
    #----------------------------------------------------------------------
    def _setStabilizerKeyframe(self,frame):
        """sets keyframe for stabilizer at the current values
        """
        # set keyframes for stabilizerParent
        self._stabilizerParent.attr('tx').setKey( t=frame, ott='step')
        self._stabilizerParent.attr('ty').setKey( t=frame, ott='step')
        self._stabilizerParent.attr('tz').setKey( t=frame, ott='step')
        
        self._stabilizerParent.attr('rx').setKey( t=frame, ott='step')
        self._stabilizerParent.attr('ry').setKey( t=frame, ott='step')
        self._stabilizerParent.attr('rz').setKey( t=frame, ott='step')
        
        self._stabilizerParent.attr('sx').setKey( t=frame, ott='step')
        self._stabilizerParent.attr('sy').setKey( t=frame, ott='step')
        self._stabilizerParent.attr('sz').setKey( t=frame, ott='step')
    
    
    
    #----------------------------------------------------------------------
    def _getParents(self, node):
        """returns hierarchycal parents of the given node
        """
        node = oyAux.getValidDagNode( node )
        
        parents = node.getAllParents()
        
        return parents
    
    
    
    #----------------------------------------------------------------------
    def _isReferenced(self, node):
        """checks if the node is referenced\n
        returns True or False
        """
        node = oyAux.getValidDagNode( node )
        
        return node.isReferenced()
    
    
    
    #----------------------------------------------------------------------
    def _createStabilizerParent(self):
        """creates the stabilizer parent
        """
        # the new stabilizer parent should be at the origin of the original
        # objects parent so that the keyframes of the object should not be altered
        
        self._stabilizerParent = oyAux.getValidDagNode( oyAux.createAxialCorrectionGroup( self._object, toParentsOrigin=True ) )
        self._stabilizerParent = oyAux.getValidDagNode( pm.rename( self._stabilizerParent, self._object.name() + "_stabilizerParent" ) )
        
        # connect it to the created nodes attribute
        index = self._object.attr('pickedData.createdNodes').numElements()
        self._stabilizerParent.attr('message') >> self._object.attr('pickedData.createdNodes['+str(index)+']')
    
    
    
    #----------------------------------------------------------------------
    def _createConstrainedParent(self):
        """creates parents for the object
        """
        # check if there is a stabilizerParent
        try:
            oyAux.getValidDagNode( self._stabilizerParent )
        except pm.MayaNodeError:
            return
        
        self._constrainedParent = oyAux.getValidDagNode( oyAux.createAxialCorrectionGroup( self._stabilizerParent ) )
        self._constrainedParent = oyAux.getValidDagNode( pm.rename( self._constrainedParent, self._object.name() + "_constrainedParent" ) )
        
        index = self._object.attr('pickedData.createdNodes').numElements()
        self._constrainedParent.attr('message') >> self._object.attr('pickedData.createdNodes['+str(index)+']')
    
    
    
    #----------------------------------------------------------------------
    def getWeightAliasList(self):
        """returns weight alias list
        """
        if not self._isSetup:
            return
        
        return self._parentConstraint.getWeightAliasList()
    
    
    
    #----------------------------------------------------------------------
    def getActiveParent(self):
        """returns the current parent
        """
        if not self._isSetup:
            return
        
        # from all the weightAlias return the one with weight 1
        weightAliases = self.getWeightAliasList()
        parents = self.getParentList()
        
        for i in range(0,len(weightAliases)):
            if weightAliases[i].get() >= 1:
                return parents[i]
        
        return None
    
    
    
    #----------------------------------------------------------------------
    def getParentList(self):
        """returns parent list
        """
        if not self._isSetup:
            return
        
        return self._parentConstraint.getTargetList()
    
    
    
    #----------------------------------------------------------------------
    def getWeightAlias(self, parent):
        """finds weightAlias of given parent\n
        if it couldn't find any it returns None
        """
        if not self._isSetup:
            return
        
        parent = oyAux.getValidDagNode( parent )
        
        assert( isinstance( parent, pm.nodetypes.Transform ) )
        
        weightAliasList = self.getWeightAliasList()
        parentList = self.getParentList()
        
        
        weightAlias = None
        
        for i in range(len(parentList)):
            if parentList[i] == parent:
                weightAlias = weightAliasList[i]
                break
        
        return weightAlias
    
    
    
    #----------------------------------------------------------------------
    def addNewParent(self, parent):
        """adds a new parent
        """
        if not self._isSetup: return
        
        parent = oyAux.getValidDagNode( parent )
        
        # check if this object is allready a parent
        if self.getWeightAlias( parent ) is not None:
            return
        
        # check if there is a cycle between parent and self._object
        if self._checkCycle( parent ):
            pm.PopupError( "Cycle Warning!!!\nnode is one of the special objects" )
            return
        
        # create parent constraint between new parent and constrained parent
        pm.parentConstraint( parent, self._constrainedParent, w=0 , mo=True)
        
        # set a keyframe for the new parent
        weightAlias = self.getWeightAlias( parent )
        weightAlias.setKey( t=0, v=0, ott='step' )
        
        # add the parent to the DAG Menu
        self.addParentToDAGMenu(parent)
    
    
    
    #----------------------------------------------------------------------
    def addParentToDAGMenu(self, parent):
        """adds the given parent to the DAG menu
        
        oyParSw - switch to --> %PARENTNAME%
        """
        # simply add "python(import oyObjectPicker as oyOP; oyOP.setObjectsParentTo( %s, %s+\".pickedData.constrainedParent[ %number% ]\" ))"
        
        commandLabel = "oyObjectPicker - switch to --> " + parent.name()
        parentIndex = self.getParentIndex( parent )
        
        if parentIndex == -1:
            return
        
        commandString = "{\n \
        int $parentIndex = "+ str(parentIndex) +";\n \
        string $parentConstraint[] = `listConnections (\"%s.pickedData.parentConstraint\")`;\n \
        string $parents[] = `parentConstraint -q -tl $parentConstraint[0]`;\n \
        string $parentName = $parents[ $parentIndex ];\n \
        python(\"import oyObjectPicker as oyOP; oyOP.setObjectsParent( '%s', '\"+$parentName+\"')\");\n \
        }"
        
        pm.mel.source("oyAddDAGMenuCommands")
        pm.mel.oyADMC_addSpecialCommandsToObject( self._object.name(), commandLabel, commandString )
    
    
    
    #----------------------------------------------------------------------
    def addDefaultOptionsToDAGMenu(self):
        """adds the default menu options to the DAG menu
        
        oyObjectPicker --> fix jump
        oyObjectPicker --> edit keyframes
        """
        pm.mel.source("oyAddDAGMenuCommands")
        
        commandLabel = "oyObjectPicker --> release object"
        commandString = "python(\"import oyObjectPicker as oyOP; oyOP.relaseObjectWithName('%s')\");"
        pm.mel.oyADMC_addSpecialCommandsToObject( self._object.name(), commandLabel, commandString )
        
        commandLabel = "oyObjectPicker --> editKeyframes"
        commandString = "python(\"import oyObjectPicker as oyOP; oyOP.editKeyframesOfObject('%s')\");"
        pm.mel.oyADMC_addSpecialCommandsToObject( self._object.name(), commandLabel, commandString )
        
        commandLabel = "oyObjectPicker --> fix jump"
        commandString = "python(\"import oyObjectPicker as oyOP; oyOP.fixJumpOnObject('%s')\");"
        pm.mel.oyADMC_addSpecialCommandsToObject( self._object.name(), commandLabel, commandString )
    
    
    
    #----------------------------------------------------------------------
    def getParentIndex(self, parent):
        """returns the given parents index
        """
        parent = oyAux.getValidDagNode( parent )
        
        parents = self.getParentList();
        
        for i in range(0,len(parents)):
            if parents[i] == parent.name():
                return i
        
        return -1
    
    
    
    #----------------------------------------------------------------------
    def getParentNameAtIndex(self, index):
        """returns the parent name at the index
        
        the index is used in the parent list of the parent constraint
        """
        parents = self.getParentList()
        return parents[index]
        
        
    
    
    
    #----------------------------------------------------------------------
    def _checkCycle(self, node):
        """checks if the given parent is a child of the self._object
        or if it is setup before to be the pickedObject and self._object
        is a parent for it
        """
        # CHECK LEVEL 1
        # check if parent is one of the special object
        if self._isSpecialObject( node ):
            return True
        
        # CHECK LEVEL 2
        # check if its a pickedObject and self._object is a parent for node
        
        # create a PickedObject with parent and get the parent list
        node = oyAux.getValidDagNode( node )
        nodeAsPickedObject = PickedObject( node )
        
        parentList = list()
        parentList = nodeAsPickedObject.getParentList()
        
        if parentList == None:
            return False
        elif len(parentList) != 0:
            # TRUE if one of the parents of the node is self._object
            if self._object in parentList:
                return True
            
            # TRUE if one of the parents of the node is a special object
            for p in parentList:
                if self._isSpecialObject( p ):
                    return True
        else:
            return False
    
    
    
    #----------------------------------------------------------------------
    def _isSpecialObject(self, node):
        """checks if node is one of the special object:\n
        constrainedParent
        stabilizerParent
        localParent
        """
        node = oyAux.getValidDagNode( node )
        
        if node == self._object or \
           node == self._constrainedParent or \
           node == self._localParent or \
           node == self._stabilizerParent:
            return True
        else:
            return False
    
    
    
    #----------------------------------------------------------------------
    def setActiveParent(self, parent):
        """sets specified parent as the active parent
        """
        if not self._isSetup:
            return
        
        parent = oyAux.getValidDagNode( parent )
        
        # get the active parent
        # if it is the same parent return
        active_parent = self.getActiveParent()
        if parent == active_parent:
            return
        
        # get the weightAlias of the specified parent
        parent_weightAlias = self.getWeightAlias( parent )
        
        # setup a new parent if it is not in the list
        if parent_weightAlias == None:
            # for now just return without doing anything
            return
        
        # get the worldMatrix of the stabilizerParent
        self._setDGDirty()
        matrix = self._getStabilizerMatrix()
        
        # set the weight of the other parents to 0 and the current to 1
        self._setParentWeight( parent )
        
        # fix dirty flag bug
        self._setDGDirty()
        
        # move the stabilizer to its new position
        self._setStabilizerMatrix(matrix)
        
        # set keyframe for stabilizer
        self._setStabilizerKeyframe( pm.currentTime(q=True) )
    
    
    
    #----------------------------------------------------------------------
    def _setDGDirty(self):
        """sets the DG to dirty for parentConstraint, constrainedParent and stabilizerParent
        """
        pm.dgdirty( self._parentConstraint, self._constrainedParent, self._stabilizerParent );
    
    
    
    #----------------------------------------------------------------------
    def _setParentWeight(self, parent):
        """sets the weight of the parent to 1 and the others to 0
        """
        parent = oyAux.getValidDagNode( parent )
        
        # get the weightAlias of the parent
        parent_weightAlias = self.getWeightAlias( parent )
        
        # set the weight of the other parents to 0 and the current to 1
        weightAliasList = self.getWeightAliasList()
        
        for weightAlias in weightAliasList:
            if weightAlias == parent_weightAlias:
                weightAlias.setKey(v=1, ott="step")
            else:
                currentWeight = weightAlias.get()
                print "currentWeight = ", currentWeight
                if currentWeight > 0:
                    weightAlias.setKey(v=0, ott="step")
    
    
    
    #----------------------------------------------------------------------
    def releaseObject(self):
        """release the object
        """
        if not self._isSetup: return
        
        # setActiveParent to localParent
        self.setActiveParent( self._localParent )
    
    
    
    #----------------------------------------------------------------------
    def fixJump(self):
        """fixes the jump in current frame
        """
        if not self._isSetup: return
        
        # delete the current parent key and set it again
        parent = self.getActiveParent()
        
        # remove the parent key at the current frame
        self.deleteCurrentParentKey()
        
        # and set the active parent again
        self.setActiveParent( parent )
    
    
    
    #----------------------------------------------------------------------
    def _getStabilizerMatrix(self):
        """returns stabilizer matrix
        """
        return pm.xform( self._stabilizerParent, q=True, ws=True, m=True )
    
    
    
    #----------------------------------------------------------------------
    def _setStabilizerMatrix(self, matrix):
        """sets stabilizer matrix to matrix
        """
        pm.xform( self._stabilizerParent, ws=True, m=matrix )
    
    
    #----------------------------------------------------------------------
    def selectAnimCurves(self):
        """selects animCurves of parentConstraint and stabilizerParent nodes for
        keyframe editing
        """
        if not self._isSetup: return
        
        pm.select( oyAux.getAnimCurves(self._parentConstraint), oyAux.getAnimCurves(self._stabilizerParent) )
    
    
    
    #----------------------------------------------------------------------
    def _setKeyframeColors(self):
        """sets the keyframe colors for the parentConstraint and stabilizerParent
        """
        # get all animCurves
        animCurves = oyAux.concatenateLists( oyAux.getAnimCurves( self._parentConstraint ), oyAux.getAnimCurves( self._stabilizerParent )) 
        
        color = [0,1,0] # green
        
        # set anim curve colors to green
        for animCurve in animCurves:
            oyAux.setAnimCurveColor( animCurve, color )
    
    
    
    #----------------------------------------------------------------------
    def deleteParentKey(self, frame):
        """deletes parent keyframes at the given keyframe
        """
        if not self._isSetup: return
        
        pm.cutKey( self._parentConstraint, self._stabilizerParent , cl=True, time=(frame,frame) )
        
    
    
    
    #----------------------------------------------------------------------
    def deleteCurrentParentKey(self):
        """deletes parent keyframes at the current keyframe 
        """
        currentFrame = pm.currentTime(q=True)
        self.deleteParentKey( currentFrame )



#----------------------------------------------------------------------
def setParent():
    import oyObjectPicker as oyOP
    selList = pm.ls(sl=True)
    
    
    if len(selList) >= 2:
        parent = selList[0]
        _object = selList[1]
        
        setObjectsParent( _object, parent )
        
    else:
        pm.PopupError( "please select first the parent, secondly the child object!!!" )



#----------------------------------------------------------------------
def setObjectsParent(_object, parent):
    import oyObjectPicker as oyOP
    selList = pm.ls(sl=True)
    
    myPickedObj = oyOP.PickedObject( _object )
    
    # before seting up check if there is a cycle with the parent
    if myPickedObj._checkCycle( parent ):
        _object = oyAux.getValidDagNode( _object )
        parent = oyAux.getValidDagNode( parent )
        pm.PopupError( "CYCLE ERROR!!!\n%s is a parent or special object for %s" % ( _object.name(), parent.name() ) )
        # do not setup any object
        return
    
    myPickedObj.setupToBePickedUp()
    myPickedObj.addNewParent( parent )
    myPickedObj.setActiveParent( parent )
    # reselect selList
    pm.select( selList )



#----------------------------------------------------------------------
def releaseObject():
    import oyObjectPicker as oyOP
    selList = pm.ls(sl=True)
    if len(selList) <= 0:
        return
    
    releaseObjectWithName( selList[0] )
    
    # reselect selList
    pm.select( selList )



#----------------------------------------------------------------------
def releaseObjectWithName( _object ):
    import oyObjectPicker as oyOP
    myPickedObj = oyOP.PickedObject( _object )
    myPickedObj.releaseObject()



#----------------------------------------------------------------------
def editKeyframes():
    import oyObjectPicker as oyOP
    selList = pm.ls(sl=True)
    if len(selList) <= 0:
        return
    editKeyframesOfObject( selList[0] )



#----------------------------------------------------------------------
def editKeyframesOfObject( _object ):
    import oyObjectPicker as oyOP
    myPickedObj = oyOP.PickedObject( _object )
    myPickedObj.selectAnimCurves()



#----------------------------------------------------------------------
def fixJump():
    import oyObjectPicker as oyOP
    selList = pm.ls(sl=True)
    fixJumpOnObject( selList[0] )
    # reselect selList
    pm.select( selList )



#----------------------------------------------------------------------
def fixJumpOnObject( _object ):
    import oyObjectPicker as oyOP
    myPickedObj = oyOP.PickedObject( _object )
    myPickedObj.fixJump()



#----------------------------------------------------------------------
def explodeSetup():
    import oyObjectPicker as oyOP
    objects = pm.ls(sl=1)
    for obj in objects:
        myPickedObj = oyOP.PickedObject( obj )
        myPickedObj.explodeSetup()